package org.banyan.senior.idempotent.interceptor;

import com.alibaba.fastjson.JSON;
import org.banyan.senior.idempotent.annotation.AutoIdempotent;
import org.banyan.senior.idempotent.bean.ResponseResult;
import org.banyan.senior.idempotent.util.RedisTokenUtil;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;

import static org.banyan.senior.idempotent.util.RedisTokenUtil.API_TOKEN;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.springframework.http.HttpStatus.OK;

/**
 * @author metalsbanyan
 * @version 1.0
 * @description: 接口幂等性 拦截器
 * @date 2023/7/21 11:22
 */
public class InterfaceIdempotenceHandlerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (support(handler)) {
            String requestHeader = request.getHeader(API_TOKEN);
            if (!StringUtils.hasLength(requestHeader)){
                writeErrorMsg(FORBIDDEN, "请求失败，请携带正确的 API token", response, "请求失败，请携带正确的 API token!!!!!");
                return false;
            }

            String apiToken = RedisTokenUtil.getOperations().get(requestHeader);
            if (!StringUtils.hasLength(apiToken)) {
                writeErrorMsg(FORBIDDEN, "请求失败，请携带正确的 API token", response, "请求失败，请携带正确的 API token!!!!!");
                return false;
            }

            if (RedisTokenUtil.validateApiToken(request, apiToken)) {
                writeErrorMsg(OK, "重复请求", response, "重复请求!!!!!");
                return false;
            }
        }
        return true;
    }

    private static void writeErrorMsg(HttpStatus forbidden, String msg, HttpServletResponse response, String x) throws IOException {
        ResponseResult<Object> responseResult = ResponseResult.builder()
                .code(forbidden.value())
                .msg(msg)
                .build();
        response.setCharacterEncoding("utf-8");
        response.getWriter().println(JSON.toJSONString(responseResult));
        response.setContentType("application/json");
        response.setStatus(forbidden.value());
        System.err.println(x);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        if (ex == null && support(handler)) {
            // 防止重复提交, 也防止token丢失
            RedisTokenUtil.setApiToken(request);
        }
    }

    private boolean support(Object handler) {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            boolean supported = handlerMethod.getBean().getClass().isAnnotationPresent(AutoIdempotent.class);
            if (supported){
                return true;
            }
            Method method = handlerMethod.getMethod();
            return method.isAnnotationPresent(AutoIdempotent.class);
        }
        return false;
    }
}